#ifndef XG_WEBX_SESS_CPP
#define XG_WEBX_SESS_CPP
///////////////////////////////////////////////////////////
#include "../sess.h"

bool LoginToken::update()
{
	return session->set("msg", toString());
}
bool LoginToken::check()
{
	CHECK_FALSE_RETURN(sid.length() > 0);

	string msg = session->get("msg");

	CHECK_FALSE_RETURN(msg.length() > 0);

	size_t len = 0;
	vector<string> vec = stdx::split(msg, ":");

	CHECK_FALSE_RETURN((len = vec.size()) > 0);

	if (len > 0) user = stdx::DecodeURL(vec[0]);
	if (len > 1) dbid = stdx::DecodeURL(vec[1]);
	if (len > 2) name = stdx::DecodeURL(vec[2]);
	if (len > 3) icon = stdx::DecodeURL(vec[3]);
	if (len > 4) mail = stdx::DecodeURL(vec[4]);
	if (len > 5) phone = stdx::DecodeURL(vec[5]);
	if (len > 6) grouplist = stdx::DecodeURL(vec[6]);
	if (len > 7) extdata.parse(stdx::DecodeURL(vec[7]));

	return true;
}
string LoginToken::toString() const
{
	string res = user;

	res += ":" + stdx::EncodeURL(dbid);
	res += ":" + stdx::EncodeURL(name);
	res += ":" + stdx::EncodeURL(icon);
	res += ":" + stdx::EncodeURL(mail);
	res += ":" + stdx::EncodeURL(phone);
	res += ":" + stdx::EncodeURL(grouplist);
	res += ":" + stdx::EncodeURL(extdata.toString());

	return std::move(res);
}
JsonElement LoginToken::toJson() const
{
	JsonElement json;

	json["user"] = user;
	json["dbid"] = dbid;
	json["name"] = name;
	json["icon"] = icon;
	json["mail"] = mail;
	json["phone"] = phone;
	json["grouplist"] = grouplist;

	const map<string, string>& map = extdata.getDataMap();

	if (map.size() > 0)
	{
		JsonElement extdata = json.addObject("extdata");

		for (auto& item : map)
		{
			extdata[item.first] = stdx::EncodeURL(item.second);
		}
	}

	return json;
}
bool LoginToken::update(CT_XG_USER& tab)
{
	user = tab.user.val();
	dbid = tab.dbid.val();
	name = tab.name.val();
	icon = tab.icon.val();
	mail = tab.mail.val();
	phone = tab.phone.val();
	grouplist = tab.grouplist.val();

	return update();
}
int LoginToken::checkTimes(int maxtimes)
{
	int times = stdx::atoi(getExtdata("times").c_str());

	if ((maxtimes -= times) > 0)
	{
		setExtdata("times", stdx::str(++times));
		update();
	}

	return maxtimes;
}
sp<LoginToken> LoginToken::Get(const string& sid)
{
	sp<LoginToken> token = newsp<LoginToken>(webx::GetSession(sid));

	return token->check() ? token : NULL;
}
sp<LoginToken> LoginToken::Create(long timeout, int minlen)
{
	auto createId = [](int len){
		string res;
		static long idx = 0;

		while (res.length() < len)
		{
			const string& key = stdx::str(rand() * rand()) + stdx::str(rand() * rand()) + stdx::str(clock()) + stdx::str(idx++);
		
			res += MD5GetEncodeString(key.c_str(), key.length(), false).val;
		}

		return res.length() > len ? res.substr(0, len) : res;
	};

	for (int i = 0; i < 10; i++)
	{
		string sid = createId(minlen);
		sp<Session> session = webx::GetSession(sid);

		if (session) continue;

		return newsp<LoginToken>(webx::GetSession(sid, timeout));
	}

	LogTrace(eERR, "create token failed");
			
	throw Exception(XG_SYSERR, "create token failed");

	return NULL;
}

string webx::GetSessionId(HttpRequest* request)
{
	size_t pos = 0;
	string sid = request->getParameter("sid");

	if (sid.length() > 0) return sid;

	return request->getCookie("sid");
}
sp<Session> webx::GetSession(const string& key, int timeout)
{
	if (RedisConnect::CanUse())
	{
		sp<RedisSession> session = newsp<RedisSession>();

		if (session->init(key, timeout)) return session;

		if (timeout > 0)
		{
			LogTrace(eERR, "create session[" + key + "][" + stdx::str(timeout) + "] failed");
			
			throw Exception(XG_SYSERR, "create session failed");
		}

		if (session->getErrorCode() == XG_NETERR)
		{
			LogTrace(eERR, "initialize session[" + key + "] failed");
			
			throw Exception(XG_SYSERR, "initialize session failed");
		}

		LogTrace(eINF, "session[" + key + "] timeout");

		return NULL;
	}

	return GetLocaleSession(key, timeout);
}
void webx::SetSessionId(HttpResponse* response, const string& sid)
{
	response->addCookie("sid", sid, 90 * 24 * 3600);
}
sp<Session> webx::GetLocaleSession(const string& key, int timeout)
{
	static HttpServer* app = HttpServer::Instance();
	sp<Session> session = app->getSession(key, timeout);
	
	if (session) return session;

	if (timeout > 0)
	{
		LogTrace(eERR, "create session[" + key + "][" + stdx::str(timeout) + "] failed");
			
		throw Exception(XG_SYSERR, "create session failed");
	}

	LogTrace(eINF, "session[" + key + "] timeout");

	return session;
}


///////////////////////////////////////////////////////////
#endif